/*
	Visp is an opensource visual performance application built with Adobe® AIR™.
	
	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
	
	Mike Creighton can be found at http://www.mikecreighton.com	
*/
package com.visp.midi
{
	import flash.filesystem.File;
	import flash.filesystem.FileStream;
	import flash.filesystem.FileMode;
	import flash.events.IOErrorEvent;
	import flash.errors.IOError;
	import flash.errors.EOFError;
	
	public class MidiSettings
	{	
		private static const _SETTINGS_NOTE_FILENAME: String = "midi_note_map.ini";
		private static const _SETTINGS_CONTROLLER_FILENAME: String = "midi_controller_map.ini";
		private static var _instance : MidiSettings;
		
		private var _inputNoteMap : Object;
		private var _inputControllerMap : Object;
		private var _noteMap : Object;
		private var _controllerMap : Object;
		
		public function MidiSettings(singletonEnforcer : MidiSettingsSingletonEnforcer)
		{	
			_noteMap = new Object();
			_inputNoteMap = new Object();
			_controllerMap = new Object();
			_inputControllerMap = new Object();
			
			loadSettings();
		}
		
		public static function getInstance() : MidiSettings
		{
			if(MidiSettings._instance == null)
				MidiSettings._instance = new MidiSettings(new MidiSettingsSingletonEnforcer());
			return MidiSettings._instance;
		}
		
		public function loadSettings() : void
		{
			var i : String;
			
			// First, tackle the NOTE MAP
			var fi : File = File.applicationStorageDirectory.resolvePath(MidiSettings._SETTINGS_NOTE_FILENAME);
			if( fi.exists ) {
				_noteMap = MidiSettings._loadObjectFromFile(fi) as Object;
				for(i in _noteMap) {
					_inputNoteMap[(_noteMap[i] as int).toString(10)] = parseInt(i, 10);
				}
			}
			// Now the CONTROLLER MAP
			fi = File.applicationStorageDirectory.resolvePath(MidiSettings._SETTINGS_CONTROLLER_FILENAME);
			if(fi.exists) {
				_controllerMap = MidiSettings._loadObjectFromFile(fi) as Object;
				for(i in _controllerMap) {
					_inputControllerMap[(_controllerMap[i] as int).toString(10)] = parseInt(i, 10);
				}
			}
		}
		
		private static function _loadObjectFromFile(file : File) : *
		{
			var stream : FileStream = new FileStream();
			try {
				stream.open(file, FileMode.READ);
			} catch (error : Error) {
				trace("General error occurred when trying to load settings in MidiSettings.");
			}
			try {
				return stream.readObject();
			} catch (error : IOError) {
				trace("An IO Error Occurred during the loadSettings.");
			} catch (eofError : EOFError) {
				trace("An EOF Error occurred during the loadSettings.");
			} finally {
				stream.close();
				stream = null;
			}
		}
		
		public function saveSettings() : void
		{
			MidiSettings._saveObjectToFile(_noteMap, File.applicationStorageDirectory.resolvePath(MidiSettings._SETTINGS_NOTE_FILENAME));
			MidiSettings._saveObjectToFile(_controllerMap, File.applicationStorageDirectory.resolvePath(MidiSettings._SETTINGS_CONTROLLER_FILENAME));
		}
		
		private static function _saveObjectToFile(object : *, file : File) : void
		{
			var stream : FileStream = new FileStream();
			try {
				stream.open(file, FileMode.WRITE);
			} catch (error : Error) {
				trace("General error occurred when trying to write settings in MidiSettings.");
			}
			try {
				stream.writeObject(object);
			} catch (error : IOError) {
				trace("An IO Error Occurred during the saveSettings.");
			} finally {
				stream.close();
				stream = null;
			}
		}
		
		public function unsetNote(noteId : int, inputId : int) : void
		{
			var noteIdStr : String = noteId.toString(10);
			var inputIdStr : String = inputId.toString(10);
			_noteMap[noteIdStr] = null;
			_inputNoteMap[inputIdStr] = null;
			delete _noteMap[noteIdStr];
			delete _inputNoteMap[inputIdStr];
		}
		
		public function setNoteInputId(noteId : int, inputId : int) : void
		{
			var noteIdStr : String = noteId.toString(10);
			var inputIdStr : String = inputId.toString(10);
			if(_noteMap[noteIdStr] > 0){
				var tempInputId : String = (_noteMap[noteIdStr] as int).toString(10);
				_inputNoteMap[tempInputId] = null;
			}
			_noteMap[noteIdStr] = inputId;
			_inputNoteMap[inputIdStr] = noteId;
		}
		
		public function getInputIdByNote(noteId : int) : int
		{
			return _noteMap[noteId.toString(10)];
		}
		
		public function getNoteIdByInput(inputId : int) : int
		{
			return _inputNoteMap[inputId.toString(10)];
		}
		
		public function unsetController(controllerId : int, inputId : int) : void
		{
			var contIdStr : String = controllerId.toString(10);
			var inputIdStr : String = inputId.toString(10);
			_controllerMap[contIdStr] = null;
			_inputControllerMap[inputIdStr] = null;
			delete _controllerMap[contIdStr];
			delete _inputControllerMap[inputIdStr];
		}
		
		public function setControllerInputId(controllerId : int, inputId : int) : void
		{
			var contIdStr : String = controllerId.toString(10);
			var inputIdStr : String = inputId.toString(10);
			if(_controllerMap[contIdStr] > 0){
				var tempInputId : String = (_controllerMap[contIdStr] as int).toString(10);
				_inputControllerMap[tempInputId] = null;
			}
			_controllerMap[contIdStr] = inputId;
			_inputControllerMap[inputIdStr] = controllerId;
		}
		
		public function getInputIdByController(controllerId : int) : int
		{
			return _controllerMap[controllerId.toString(10)];
		}
		
		public function getControllerIdByInput(inputId : int) : int
		{
			return _inputControllerMap[inputId.toString(10)];
		}
	}
}

internal class MidiSettingsSingletonEnforcer {}